﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Reflection;
using System.Collections;

namespace ConsumeSys.Orm
{
    /// <summary>
    /// 数据实体模型转换
    /// </summary>
    public class EntityBase
    {
        /// <summary>
        /// 指定搜索类型
        /// </summary>
        private const BindingFlags BindingFlag = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
        /// <summary>
        /// 保存实体的属性和类型
        /// </summary>
        private static Dictionary<Type, Dictionary<string, PropertyInfo>> propertyMappings = new Dictionary<Type, Dictionary<string, PropertyInfo>>();

        /// <summary>
        /// 执行分页查询
        /// </summary>
        /// <param name="orderby">排序语句</param>
        /// <param name="tableName">表名称</param>
        /// <param name="sqlWhere">查询条件</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页大小</param>
        /// <returns>ArrayList</returns>
        public static ArrayList ExecutePageingSQL<T>(string orderby, string tableName, string sqlWhere, int pageIndex, int pageSize) where T : new()
        {
            //查询分页数据
            DataSet ds = DBHelper.SQLHepler.GetPagingDataSet(orderby, tableName, sqlWhere, pageIndex, pageSize);
            //循环查询结果进行赋值
            List<T> _list = DataTableToList<T>(ds.Tables[0]);
            //总记录数  
            int recordCount = Convert.ToInt32(ds.Tables[1].Rows[0][0]);
            //计算总页数
            int pageCount = ((recordCount % pageSize == 0) ? (recordCount / pageSize) : (recordCount / pageSize + 1));
            //保存数据
            ArrayList _arrayList = new ArrayList();
            _arrayList.Add(pageIndex);
            _arrayList.Add(recordCount);
            _arrayList.Add(pageCount);
            _arrayList.Add(_list);
            return _arrayList;
        }

        /// <summary>
        /// DataTable转换为实体模型list
        /// </summary>
        /// <typeparam name="T">需要转换的目标类型</typeparam>
        /// <param name="dt">需要转换的DataTable</param>
        /// <returns>List</returns>
        public static List<T> DataTableToList<T>(DataTable dt) where T : new()
        {
            return GetComplexEntities<T>(dt);
        }

        /// <summary>
        /// DataTable转换为Model
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="dt">需要转换的DataTable</param>
        /// <returns>目标类型</returns>
        public static T DataTableToModel<T>(DataTable dt) where T : new()
        {
            List<T> _list = GetComplexEntities<T>(dt);
            if (_list != null && _list.Count > 0)
            {
                return _list[0];
            }
            else
            {
                return new T();
            }
        }

        /// <summary>
        /// 进行模型转换操作
        /// </summary>
        /// <typeparam name="T">需要转换的目标类型</typeparam>
        /// <param name="dt">需要转换的DataTable</param>
        /// <returns>List</returns>
        private static List<T> GetComplexEntities<T>(DataTable dt) where T : new()
        {
            List<T> _list = new List<T>();
            if (dt != null && dt.Rows.Count > 0)
            {
                if (!propertyMappings.ContainsKey(typeof(T)))
                {
                    GenerateTypePropertyMapping(typeof(T));
                }
                Dictionary<string, PropertyInfo> propertyMapping = propertyMappings[typeof(T)];
                T t;
                foreach (DataRow itemRow in dt.Rows)
                {
                    t = new T();
                    foreach (KeyValuePair<string, PropertyInfo> itemProperty in propertyMapping)
                    {
                        var key = itemProperty.Value.CustomAttributes.FirstOrDefault();                    
                        object[] obj = itemProperty.Value.GetCustomAttributes(true);
                        if (obj != null && obj.Length > 0 && key.AttributeType.FullName != "System.ComponentModel.DataAnnotations.KeyAttribute")
                        {                           
                            FKAttribute fk = (FKAttribute)obj[0];
                            if (!fk.IsFK)
                            {
                                itemProperty.Value.SetValue(t, GetValueFromObject(itemRow[itemProperty.Key], itemProperty.Value.PropertyType), null);
                            }
                        }
                        else
                        {
                            //2019-11-13 23:23:42 王浩力 修改
                            if (itemRow[itemProperty.Key] is System.DBNull)
                            {
                                itemProperty.Value.SetValue(t, default);
                            }
                            else
                            {
                                itemProperty.Value.SetValue(t, itemRow[itemProperty.Key]);
                            }
                            //itemProperty.Value.SetValue(t, GetValueFromObject(itemRow[itemProperty.Key], itemProperty.Value.PropertyType), null);
                        }
                    }
                    _list.Add(t);
                }
            }
            return _list;
        }

        /// <summary>
        /// 获取Type的属性
        /// </summary>
        /// <param name="type">目标类型</param>
        private static void GenerateTypePropertyMapping(Type type)
        {
            if (type != null)
            {
                PropertyInfo[] propertyArry = type.GetProperties(BindingFlag);
                Dictionary<string, PropertyInfo> propertyMapping = new Dictionary<string, PropertyInfo>(propertyArry.Length);
                foreach (PropertyInfo item in propertyArry)
                {
                    propertyMapping.Add(item.Name, item);
                }
                propertyMappings.Add(type, propertyMapping);
            }
        }

        /// <summary>
        /// 值转换
        /// </summary>
        /// <param name="val">值</param>
        /// <param name="targetType">类型</param>
        /// <returns>转换后的值</returns>
        private static object GetValueFromObject(object val, Type targetType)
        {
            if (targetType == typeof(string))
            {
                return GetString(val);
            }
            else
            {
                return GetNonGenericValueFromObject(val, targetType);
            }
        }

        /// <summary>  
        /// 将指定的 Object 的值转换为指定类型的值。  
        /// </summary>  
        /// <param name="value">实现 IConvertible 接口的 Object，或者为 null</param>  
        /// <param name="targetType">目标对象的类型</param>  
        /// <returns>object</returns>  
        private static object GetNonGenericValueFromObject(object value, Type targetType)
        {
            switch (targetType.Name)
            {
                case "Byte": return GetByte(value);
                case "SByte": return GetSByte(value);
                case "Char": return GetChar(value);
                case "Boolean": return GetBoolean(value);
                case "Guid": return GetGuid(value);
                case "Int16": return GetInt16(value);
                case "UInt16": return GetUInt16(value);
                case "Int32": return GetInt32(value);
                case "UInt32": return GetUInt32(value);
                case "Int64": return GetInt64(value);
                case "UInt64": return GetUInt64(value);
                case "Single": return GetSingle(value);
                case "Double": return GetDouble(value);
                case "Decimal": return GetDecimal(value);
                case "DateTime": return GetDateTime(value);
                case "TimeSpan": return GetTimeSpan(value);
                default: return value;
            }
        }

        #region 数据类型转换

        /// <summary>  
        /// 将Object转换成字符串类型  
        /// </summary>  
        /// <param name="value">object类型的实例</param>  
        /// <returns></returns>  
        private static object GetString(object value)
        {
            return Convert.ToString(value);
        }

        /// <summary>  
        /// 将指定的 Object 的值转换为指定枚举类型的值。  
        /// </summary>  
        /// <param name="value">实现 IConvertible 接口的 Object，或者为 null</param>  
        /// <returns></returns>  
        private static object GetBoolean(object value)
        {
            if (value is Boolean)
            {
                return value;
            }
            else
            {
                byte byteValue = (byte)GetByte(value);
                if (byteValue == 0)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }

        /// <summary>  
        /// 将指定的 Object 的值转换为指定枚举类型的值。  
        /// </summary>  
        /// <param name="value">实现 IConvertible 接口的 Object，或者为 null</param>  
        /// <returns></returns>  
        private static object GetByte(object value)
        {
            if (value is Byte)
            {
                return value;
            }
            else
            {
                return byte.Parse(value.ToString());
            }
        }

        /// <summary>  
        /// 将指定的 Object 的值转换为指定枚举类型的值。  
        /// </summary>  
        /// <param name="value">实现 IConvertible 接口的 Object，或者为 null</param>  
        /// <returns></returns>  
        private static object GetSByte(object value)
        {
            if (value is SByte)
            {
                return value;
            }
            else
            {
                return SByte.Parse(value.ToString());
            }
        }

        /// <summary>  
        /// 将指定的 Object 的值转换为指定枚举类型的值。  
        /// </summary>  
        /// <param name="value">实现 IConvertible 接口的 Object，或者为 null</param>  
        /// <returns></returns>  
        private static object GetChar(object value)
        {
            if (value is Char)
            {
                return value;
            }
            else
            {
                return Char.Parse(value.ToString());
            }
        }

        /// <summary>  
        /// 将指定的 Object 的值转换为指定枚举类型的值。  
        /// </summary>  
        /// <param name="value">实现 IConvertible 接口的 Object，或者为 null</param>  
        /// <returns></returns>  
        private static object GetGuid(object value)
        {
            if (value is Guid)
            {
                return value;
            }
            else
            {
                return new Guid(value.ToString());
            }
        }

        /// <summary>  
        /// 将指定的 Object 的值转换为指定枚举类型的值。  
        /// </summary>  
        /// <param name="value">实现 IConvertible 接口的 Object，或者为 null</param>  
        /// <returns></returns>  
        private static object GetInt16(object value)
        {
            if (value is Int16)
            {
                return value;
            }
            else
            {
                return Int16.Parse(value.ToString());
            }
        }

        /// <summary>  
        /// 将指定的 Object 的值转换为指定枚举类型的值。  
        /// </summary>  
        /// <param name="value">实现 IConvertible 接口的 Object，或者为 null</param>  
        /// <returns></returns>  
        private static object GetUInt16(object value)
        {
            if (value is UInt16)
            {
                return value;
            }
            else
            {
                return UInt16.Parse(value.ToString());
            }
        }

        /// <summary>  
        /// 将指定的 Object 的值转换为指定枚举类型的值。  
        /// </summary>  
        /// <param name="value">实现 IConvertible 接口的 Object，或者为 null</param>  
        /// <returns></returns>  
        private static object GetInt32(object value)
        {
            if (value is Int32)
            {
                return value;
            }
            else
            {
                return Int32.Parse(value.ToString());
            }
        }

        /// <summary>  
        /// 将指定的 Object 的值转换为指定枚举类型的值。  
        /// </summary>  
        /// <param name="value">实现 IConvertible 接口的 Object，或者为 null</param>  
        /// <returns></returns>  
        private static object GetUInt32(object value)
        {
            if (value is UInt32)
            {
                return value;
            }
            else
            {
                return UInt32.Parse(value.ToString());
            }
        }

        /// <summary>  
        /// 将指定的 Object 的值转换为指定枚举类型的值。  
        /// </summary>  
        /// <param name="value">实现 IConvertible 接口的 Object，或者为 null</param>  
        /// <returns></returns>  
        private static object GetInt64(object value)
        {
            if (value is Int64)
            {
                return value;
            }
            else
            {
                return Int64.Parse(value.ToString());
            }
        }

        /// <summary>  
        /// 将指定的 Object 的值转换为指定枚举类型的值。  
        /// </summary>  
        /// <param name="value">实现 IConvertible 接口的 Object，或者为 null</param>  
        /// <returns></returns>  
        private static object GetUInt64(object value)
        {
            if (value is UInt64)
            {
                return value;
            }
            else
            {
                return UInt64.Parse(value.ToString());
            }
        }

        /// <summary>  
        /// 将指定的 Object 的值转换为指定枚举类型的值。  
        /// </summary>  
        /// <param name="value">实现 IConvertible 接口的 Object，或者为 null</param>  
        /// <returns></returns>  
        private static object GetSingle(object value)
        {
            if (value is Single)
            {
                return value;
            }
            else
            {
                return Single.Parse(value.ToString());
            }
        }

        /// <summary>  
        /// 将指定的 Object 的值转换为指定枚举类型的值。  
        /// </summary>  
        /// <param name="value">实现 IConvertible 接口的 Object，或者为 null</param>  
        /// <returns></returns>  
        private static object GetDouble(object value)
        {
            if (value is Double)
            {
                return value;
            }
            else
            {
                return Double.Parse(value.ToString());
            }
        }

        /// <summary>  
        /// 将指定的 Object 的值转换为指定枚举类型的值。  
        /// </summary>  
        /// <param name="value">实现 IConvertible 接口的 Object，或者为 null</param>  
        /// <returns></returns>  
        private static object GetDecimal(object value)
        {
            if (value is Decimal)
            {
                return value;
            }
            else
            {
                return Decimal.Parse(value.ToString());
            }
        }

        /// <summary>  
        /// 将指定的 Object 的值转换为指定枚举类型的值。  
        /// </summary>  
        /// <param name="value">实现 IConvertible 接口的 Object，或者为 null</param>  
        /// <returns></returns>  
        private static object GetDateTime(object value)
        {
            if (value is DateTime)
            {
                return value;
            }
            else
            {
                return DateTime.Parse(value.ToString());
            }
        }

        /// <summary>  
        /// 将指定的 Object 的值转换为指定枚举类型的值。  
        /// </summary>  
        /// <param name="value">实现 IConvertible 接口的 Object，或者为 null</param>  
        /// <returns></returns>  
        private static object GetTimeSpan(object value)
        {
            if (value is TimeSpan)
            {
                return value;
            }
            else
            {
                return TimeSpan.Parse(value.ToString());
            }
        }

        #endregion

    }
}
